use std::ops::Deref;

use bytes::{Buf, BytesMut};

use crate::{RespDecode, RespEncode, RespError};

use super::{parse_length, CRLF_LEN};

impl RespDecode for BulkString {
    const PREFIX: &'static str = "$";

    fn decode(buf: &mut BytesMut) -> Result<Self, RespError> {
        let (end, len) = parse_length(buf, Self::PREFIX)?;

        // 获取被留下来的数据
        let remained = &buf[end + CRLF_LEN..];
        if remained.len() < len + CRLF_LEN {
            return Err(RespError::NotComplete);
        }
        buf.advance(end + CRLF_LEN);
        let data = buf.split_to(len + CRLF_LEN);
        Ok(BulkString::new(data[..len].to_vec()))
    }

    fn expect_length(buf: &[u8]) -> Result<usize, RespError> {
        let (end, len) = parse_length(buf, Self::PREFIX)?;
        Ok(end + CRLF_LEN + len + CRLF_LEN)
    }
}

// bulk string: "$<length>\r\n<data>\r\n"
// 先为bulk string的类型实现 encode 方法
impl RespEncode for BulkString {
    fn encode(self) -> Vec<u8> {
        let len = self.len();
        let mut buf = Vec::with_capacity(len + 16);
        let first_value = format!("${}\r\n", len);
        buf.extend_from_slice(&first_value.into_bytes());
        buf.extend_from_slice(&self);
        buf.extend_from_slice(b"\r\n");
        buf
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub struct BulkString(pub(crate) Vec<u8>);

impl Deref for BulkString {
    type Target = Vec<u8>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl BulkString {
    #[allow(dead_code)]
    pub fn new(s: impl Into<Vec<u8>>) -> Self {
        Self(s.into())
    }
}

// 字符串切面直接转换成 BulkString
impl From<&str> for BulkString {
    fn from(value: &str) -> Self {
        Self::new(value)
    }
}
// u8数组引用直接转换成 BulkString
impl From<&[u8]> for BulkString {
    fn from(value: &[u8]) -> Self {
        Self::new(value)
    }
}
impl From<String> for BulkString {
    fn from(value: String) -> Self {
        Self::new(value)
    }
}

// 固定长度的 u8数组引用直接转换成 BulkString
impl<const N: usize> From<&[u8; N]> for BulkString {
    fn from(value: &[u8; N]) -> Self {
        Self::new(value)
    }
}
impl AsRef<[u8]> for BulkString {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

#[cfg(test)]
mod tests {
    use anyhow::Result;
    use bytes::BytesMut;

    use crate::{bulk_string::BulkString, RespDecode, RespEncode};

    #[test]
    fn test_bulk_string_decode() -> Result<()> {
        let mut buf = BytesMut::new();
        buf.extend_from_slice(b"$5\r\nhello\r\n");
        let frame = BulkString::decode(&mut buf)?;
        assert_eq!(frame, BulkString::new("hello".to_string()));
        Ok(())
    }

    #[test]
    fn test_bulk_string_encode() {
        let buf = BulkString::new("hello".as_bytes().to_vec()).encode();
        assert_eq!(buf, b"$5\r\nhello\r\n");
    }
}
